<?php
/*******************************************************************************

    FinalsClub.org is a platform for students and faculty to collaborate
    and share their knowledge with the world.

    Copyright (C) 2009  Andrew Magliozzi

    This file is a part of FinalsClub.org.

    FinalsClub.org is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

    To contact FinalsClub.org, send an email to info@finalsclub.org, or
    send mail to Finals Club, c/o Veritas Tutors, 1132 Massachusetts Avenue,
    Cambridge, MA 02138.

*******************************************************************************/

/**
 * users actions.
 *
 * @package    FinalsClub
 * @subpackage users
 * @author     Your name here
 * @version    SVN: $Id: actions.class.php 9301 2008-05-27 01:08:46Z dwhittle $
 */
class usersActions extends sfActions {
	
	public function executeHome(sfWebRequest $reqeust) {
		$page = null;
		if($this->request->hasParameter('page'))
			$page = $this->request->getParameter('page');
		$this->feeds = ActivityFeedPeer::retrieveByUserId($this->getUser()->getId(), $page);
	}
	
	/**
	 * Presents a form with various input fields for creating a user. The result of this
	 * action basically renders the registration page
	 * @param $request
	 * @return sfView::SUCCESS
	 */	 
	public function executeEdit(sfWebRequest $request) {
		$user_profile = UserProfilePeer::retrieveByUserId($this->getUser()->getId());
		$this->profile_form = new UserProfileForm($user_profile);
		
		$user = UserPeer::retrieveById($this->getUser()->getId());
		$this->user = $user;
		$this->user_form = new UserForm($user);
		$this->prof = ProfPeer::retrieveByUserId($user->getId());
		echo print_r($this->prof); 
		$this->form = new UserProfileForm($user_profile);
		$this->form->embedForm('user', new UserForm($user));
		
		}	
	 
	public function executeNew(sfWebRequest $request) {
		$this->form = new UserForm();
		if($this->getUser()->hasFlash('invited')) {
			if($this->getUser()->hasFlash('email')) {
				$email = $this->getUser()->getFlash('email');
				$this->form->setDefault('user[email]', $email);
			}
			$this->getUser()->setFlash('invited', true);
		}
	}

	/**
	 * Performs the actual creation of a user if the request method is a post
	 * @param $request
	 * @return sfView::SUCCESS
	 */
	public function executeCreate(sfWebRequest $request) {
	    $this->forward404Unless($request->isMethod('post'));	
	    $user_request = $request->getParameter('user');
	    
	    //grab the pre-made user object, if there is one
	    $user = UserPeer::retrieveByEmail($user_request['email']);
	    if(!$user || $user->getActivated() == 1)
	    	$user = new User();
	    $this->form = new UserForm($user);

	    // set a month and day for the birthdate to jan 1 since users only require their birth year
	    $user_request['birthdate']['month'] = "1";
	    $user_request['birthdate']['day'] = "1";
	    
	
	    $this->form->bind($user_request, array());
		$error = false;
	    // make sure the network they pick matches the domain email for Harvard
		if(UserPeer::$networks[$user_request['network_id']] == 'Harvard' && trim(substr($user_request['email'], -11)) != 'harvard.edu') {
			$this->getUser()->setFlash('error', "You're email address must belong to the harvard.edu domain");
			$error = true;
		}
	
	
	    if(!$error && $this->form->isValid()) {
	      $user = $this->form->updateObject();   
	      $network_id = $user->getNetworkId();
	      if(UserPeer::$networks[$network_id] == 'Other')		// check if the network id corresponds to 'Other' in networks array
	      		$network_name = $this->form->getValue('network_name');
	      else
	      		$network_name = $user->getNetworkDisplayName();
		  $user->setNetworkName($network_name);
	      $user->setMd5Password(md5($this->form->getValue('password')));
	      $user->setLanguage('en');
	      $user->setActivated(0);	// this account is new and needs to be activated
	      $user->save();
	      
	      // add a new a.nnotate server account for this user, this allows document uploading and annotation
	      $annotate_email = $user->getEmail();
	      $annotate_sig = $user->getUsername();
	      $annotate_api = new AnnotateApi();
	      $annotate_api->createAccount($annotate_email, $annotate_sig);

	      // now we need a user activation object for this account
	      $activation = new UserActivation();
	      
    	  $token = substr(md5(time()),4,11);		// our token is the 11 characters after the first four of a md5 hash of the current unix timestamp
		  $activation->setToken($token);			// set the token
		  $activation->setUserId($user->getId());	// set the user_id
		  
		  $activation->save();		// save object to the database
	      
	      // now what we need to do is generate an activation url to email the user      
	      $activation_url = $this->generateUrl('activation', array('id'=>$activation->getId(), 'token'=>$activation->getToken()), true);
	      
	      // retrieve the smtp server from the app.yml
		  $smtp_server = sfConfig::get('app_smtp_server');
		  $smtp_user = sfConfig::get('app_smtp_user');
		  $smtp_password = sfConfig::get('app_smtp_password');
		  try
		  {
		    // Create the mailer
		    $connection = new Swift_Connection_SMTP($smtp_server, 465, Swift_Connection_SMTP::ENC_SSL);
		    $connection->setUsername($smtp_user);
		    $connection->setPassword($smtp_password);
		    $mailer = new Swift($connection);  
		  
		  	// Subject line
		  	$message = new Swift_Message('Welcome to FinalsClub.org');
		 
		  	// Render message parts - do a network check to determine which message
		  	$mailContext = array('name'=>$user->getFullName(), 'url'=>$activation_url, 'school_name'=> $user->getNetworkName());	// to be passed as parameters to the partials
		  	$message->attach(new Swift_Message_Part($this->getPartial('welcomeToFinalsClubHtml', $mailContext), 'text/html'));		// HTML e-mail body
		  	$message->attach(new Swift_Message_Part($this->getPartial('welcomeToFinalsClubPlain', $mailContext), 'text/plain'));	// Plaintext e-mail body
		 
		  	// Set the 'To' and 'From' fields
		  	$mailer->send($message, $user->getEmail(), $smtp_user);
		  	$mailer->disconnect();
		  }
		  catch (Exception $e)
		  {
		    $this->logMessage($e->getMessage(), 'crit');	// Log the exception as critical
		  	$this->getUser()->setFlash('warning', 'Failed to initialize mailer!');		// alert the user e-mailing failed
		  }
	      
	      if($this->getUser()->hasFlash('invited')) {	// check for the flash variable 'invited' which indicates the user is registering from a invitation link
	      	if($this->getUser()->getFlash('invited')) {
	      		$invitation = InvitationPeer::retrieveByEmail($user->getEmail());	// get invitation object
	      		if($invitation instanceOf Invitation) {		// check for a valid invitation object
	      			$invitation->setRecipientId($user->getId());	// set the recipient_id of the invitation
	      			$invitation->setStatus(InvitationPeer::ACCEPTED);	// set the invitation status to 'ACCEPTED' (2)
	      			$invitation->save();
	      		}
	      	}
	      }
		  
	      $this->getUser()->setFlash('success', 'Your account has been successfully created. A verification email has been sent to your inbox. Please use the activation link in your email to verify your account.');
	      // Log in the user
	    } else {
		    $this->setTemplate('new');		
		}
	}
	
	public function executeFacebookmember(sfWebRequest $request) {
		$fb_uid = $this->checkForFacebookMember();
		
	    $user = new User();
	    $this->form = new UserFacebookForm($user);
	    
		$user = $request->getParameter('user');
//	    $user['birthdate']['month'] = "1";
//	    $user['birthdate']['day'] = "1";

		$user['md5_password'] = md5("finalsclub1");

		$this->form->bind($user, array());
		if($this->form->isValid()) {
		  $user = $this->form->updateObject();
	      $colleges = FacebookUtility::get_colleges_list_by_id($fb_uid);
	      
          $collegeName = null;
	      $network_id = null;
	      if (empty($colleges)) {
              $collegeName = 'Other';
	      	  $network_id = 10;
	      } else {
		      $collegeName = $colleges[0]['name'];
		      foreach (UserPeer::$networks as $key => $value) {
		      	  if (strcasecmp($value, $collegeName) == 0)
		      	  	$network_id = $key;
		      }
		      if ($network_id == null) {
		      	  $network_id = 10;
		      }
	      }
	      $user->setFacebookId($fb_uid);
	      
	      $user->setNetworkId($network_id);
	      $user->setNetworkName($collegeName);
	      
          $user->setAvatar(FacebookUtility::get_info($user->getFacebookId(), 'pic_big'));
	      $user->setFirstName(FacebookUtility::get_info($user->getFacebookId(), 'first_name'));
	      $user->setLastName(FacebookUtility::get_info($user->getFacebookId(), 'last_name'));
	      
	      $user->setCountry('US');
	      $user->setLanguage('en');
	      $user->setActivated(1);	// this account is new and needs to be activated
	      $user->save();
	      
	      
          $profile = UserProfilePeer::retrieveByUserId($user->getId());
	      if ($profile == null) {
	      	  $profile = new UserProfile();
	      	  $profile->setUserId($user->getId());
	      }
//	      $current_location = FacebookUtility::get_info($user->getFacebookId(), 'current_location');
//	      $profile->setCity($current_location['city']);
	      
	      $profile->setFavoriteBooks(FacebookUtility::get_info($user->getFacebookId(), 'books'));
	      $profile->setAboutMe(FacebookUtility::get_info($user->getFacebookId(), 'about_me'));
//	      $profile->setWebsite(FacebookUtility::get_info($user->getFacebookId(), 'website'));
	      $profile->save();
      
	      // add a new annotate server account for this user, this allows document uploading and annotation
	      $annotate_email = $user->getEmail();
	      $annotate_sig = $user->getUsername();
	      $annotate_api = new AnnotateApi();
	      $annotate_api->createAccount($annotate_email, $annotate_sig);
	
	      // now we need a user activation object for this account
	      $activation = new UserActivation();
	      
	      $token = substr(md5(time()),4,11);		// our token is the 11 characters after the first four of a md5 hash of the current unix timestamp
		  $activation->setToken($token);			// set the token
		  $activation->setUserId($user->getId());	// set the user_id
		  $activation->save();		// save object to the database
	      
	      $this->setTemplate('new');
	      $this->getUser()->setFlash('success', 'Your account has been successfully created!');
	      // Log in the user
	      $this->getUser()->login($user->getId());
		  $this->redirect('user_profiles/edit');	
		}
	  $this->setTemplate('facebookmember');	
	}
	
	public function executeFacebook(sfWebRequest $request) {
		$this->checkForFacebookMember();
		
		$this->form = new UserFacebookForm();
		$this->setTemplate('facebookmember');
	}
	
	private function checkForFacebookMember() {
		$fb_uid = FacebookUtility::facebook_client()->get_loggedin_user();
		if (!$fb_uid) {
			throw new Exception('No authenticated facebook user');
		}
		$existing_fb_user = UserPeer::retrieveByFacebookId($fb_uid);
		if ($existing_fb_user != null) {
			$this->getUser()->login($existing_fb_user->getId());
			$this->redirect('user_profiles/show');
		}
		return $fb_uid;
	}
	
	/**
	 * Handles activation links generated at registration. Verifies the activation record id and token, if the
	 * record exists and the token matches the function sets the user account to activated and deletes the 
	 * activation record. Then the user is sent to edit their profile.
	 *
	 * @param $request
	 * @return user_profiles/edit on success, site/home on failure
	 */
	public function executeActivate($request) {
		$aid = $request->getParameter('id');	// activation record id
		$token = $request->getParameter('token');	// corresponding token
		if(!empty($aid) && !empty($token) && $activation = UserActivationPeer::retrieveById($aid)) {
			// compare the token from the request with the token in the database
			if(strcmp($token, $activation->getToken()) === 0) {
				$user = UserPeer::retrieveById($activation->getUserId());	// retrieve the user object
				$user->setActivated(1);		// set the account to activated
				$user->save();		// save object
				
				// we no longer need the activation database entry
				$activation->delete();
			
				$this->getUser()->setFlash('success', 'Your account has been activated');
				$this->getUser()->login($user->getId());	// login the user
				$this->redirect('user_profiles/edit');		// send them to edit their profile
			}
			else {
				$this->getUser()->setFlash('warning', 'The link you clicked was invalid!');
			}
		}
		else {	// possibly because the activation_id (aid) and/or token were blank or the activation record did not exist
			$this->getUser()->setFlash('warning', 'Incomplete request');
		}
		$this->redirect('site/home');	// either way on failure redirect to home
	}
	
	
	/**
	 * Presents the login page. If the request method is a post, it will validate the user and log
	 * them in if the validation was successful. Upon successful login, the user's id and username
	 * will be stored on their session.
	 * @param $request
	 * @return sfView::SUCCESS
	 */
	public function executeLogin($request) {
		$this->form = new LoginForm();	
		if($request->isMethod('post')) {
			$this->form->bind($request->getParameter('login'), array());
			if($this->form->isValid()) {
			  $user = $this->form->getValue('user');
			  if($user->getActivated()) {
				 $this->getUser()->setFlash('success', 'You have successfully logged in!');
				 $this->getUser()->login($user->getId());
				 /* Now we need to check how many times the user has logged in to determine the proper routing
				    If the user has logged in less than four times redirect them to the home tab, otherwise profile
				 */
				 $login_count = $user->getLoginCount();
				 $login_count++;
				 if($login_count < 4) {
				 	// if the user has logged in less than four times, send them to the home tab and increment the login_count
				 	$referer = 'site/home';
				 	$user->setLoginCount($login_count);
				 	$user->save();
				 }
				 else {
				 	$referer = 'user_profiles/show';
				 }
				 $this->redirect($referer);
			  } else {
				 $this->getUser()->setFlash('error', "You must verify your email address. Please check your email");
			  }
			} else {
				// persist the previous referer
				$this->getRequest()->setAttribute('referer', $request->getParameter('referer'));
			}
		} else {
			$this->getRequest()->setAttribute('referer', $this->getRequest()->getReferer());			
		}
	}
	
	/**
	 * Logout a user and redirect them back to the login page
	 * @param $request
	 * @return sfView::SUCCESS
	 */
	public function executeLogout($request) {
		$this->getUser()->logout();
		$this->getUser()->setFlash('success', 'You have successfully logged out!');		
		$this->redirect('users/login');
	}

        /**
         * Outputs an A.nnotate Login URL that the browser uses to login to the user's annotate session
         *
         * @param sfRequest $request A request object
         */
        public function executeGetannologin(sfWebRequest $request)
        {
	  if (!$this->getUser()->isAuthenticated()) {
	    return $this->renderText("");
	  }

	  sfLoader::loadHelpers(array('Url'));
	  $annotate_api = new AnnotateApi();
	  $user = UserPeer::retrieveById($this->getUser()->getId());
	  $login_url = $annotate_api->getLoginURL($user->getEmail(), url_for('users/annologinsuccess',true), "about:blank");

	  return $this->renderText($login_url);
        }

        /**
         * Outputs javascript for UI feedback.  This is called after a successful A.nnotate login
         *
         * @param sfRequest $request A request object
         */
        public function executeAnnologinsuccess(sfWebRequest $request)
        {
	  return $this->renderText("");
        }
	
}
